package com.dragon.backstage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dragon.backstage.convert.RoleConvert;
import com.dragon.backstage.convert.UserConvert;
import com.dragon.backstage.domain.param.role.RoleAddParam;
import com.dragon.backstage.domain.param.role.RoleAuthUserAddBatchParam;
import com.dragon.backstage.domain.param.role.RoleAuthUserDeleteBatchParam;
import com.dragon.backstage.domain.param.role.RoleAuthUserParam;
import com.dragon.backstage.domain.param.role.RoleChangeStatusParam;
import com.dragon.backstage.domain.param.role.RoleEditParam;
import com.dragon.backstage.domain.param.role.RoleParam;
import com.dragon.backstage.domain.vo.role.RoleDetailVo;
import com.dragon.backstage.domain.vo.role.RoleVo;
import com.dragon.backstage.domain.vo.user.UserVo;
import com.dragon.backstage.service.RoleMenuService;
import com.dragon.backstage.service.RoleService;
import com.dragon.backstage.service.UserRoleService;
import com.dragon.common.domain.vo.PaginationVo;
import com.dragon.common.utils.AjaxResult;
import com.dragon.interfaces.constant.RoleConstant;
import com.dragon.interfaces.domain.request.role.RoleRequest;
import com.dragon.interfaces.domain.request.user.UserRequest;
import com.dragon.interfaces.entity.Role;
import com.dragon.interfaces.entity.RoleMenu;
import com.dragon.interfaces.entity.User;
import com.dragon.interfaces.entity.UserRole;
import com.dragon.interfaces.mapper.RoleMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragon.interfaces.mapper.RoleMenuMapper;
import com.dragon.interfaces.mapper.UserMapper;
import com.dragon.interfaces.mapper.UserRoleMapper;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色信息表 服务实现类
 * </p>
 *
 * @author dragon
 * @since 2024-08-01 18:05:42
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private UserRoleService userRoleService;


    /**
     * 角色列表
     *
     * @param param 角色搜索请求参数
     * @return 角色列表
     */
    @Override
    public AjaxResult<PaginationVo<RoleVo>> roleList(RoleParam param) {
        List<RoleVo> roleVos = new ArrayList<>();

        RoleRequest roleRequest = RoleConvert.toRoleRequest(param);

        Integer roleTotal = roleMapper.selectRoleCount(roleRequest);
        List<Role> roleList = roleMapper.selectRoleList(roleRequest);

        if (CollectionUtils.isNotEmpty(roleList)) {
            for (Role role : roleList) {
                roleVos.add(RoleConvert.toRoleVo(role));
            }
        }

        return AjaxResult.succeedWith(PaginationVo
            .<RoleVo>builder()
            .total(roleTotal)
            .rows(roleVos)
            .build()
        );
    }

    /**
     * 角色详情
     *
     * @param roleId 角色ID
     * @return 角色详情
     */
    @Override
    public AjaxResult<RoleDetailVo> roleDetail(Long roleId) {
        if (Objects.isNull(roleId) || roleId.equals(0L)) {
            return AjaxResult.failed("角色ID不能为空");
        }

        Role role = roleMapper.selectById(roleId);
        if (Objects.isNull(role)) {
            return AjaxResult.failed("角色不存在");
        }

        // 获取角色拥有的菜单
        List<Long> roleMenuIds = roleMenuMapper.getRoleMenuIds(roleId);

        return AjaxResult.succeedWith(RoleConvert.toRoleDetailVo(role, roleMenuIds));
    }

    /**
     * 添加角色
     *
     * @param param 添加角色请求参数
     * @return 添加结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<Void> addRole(RoleAddParam param) {
        AjaxResult<Void> check = RoleAddParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        boolean existRoleNameFlag = roleMapper.exists(new QueryWrapper<Role>()
            .eq(Role.ROLE_NAME, param.getRoleName())
        );
        if (existRoleNameFlag) {
            return AjaxResult.failed("角色名称已存在");
        }
        boolean existRoleKeyFlag = roleMapper.exists(new QueryWrapper<Role>()
            .eq(Role.ROLE_KEY, param.getRoleKey())
        );
        if (existRoleKeyFlag) {
            return AjaxResult.failed("权限字符已存在");
        }

        try {
            addRoleHandle(param);
        } catch (Exception e) {
            return AjaxResult.failed("角色添加失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 编辑角色
     *
     * @param param 编辑角色请求参数
     * @return 编辑结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<Void> editRole(RoleEditParam param) {
        AjaxResult<Void> check = RoleEditParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        Role role = roleMapper.selectById(param.getRoleId());
        if (Objects.isNull(role)) {
            return AjaxResult.failed("角色不存在");
        }

        boolean existRoleNameFlag = roleMapper.exists(new QueryWrapper<Role>()
            .eq(Role.ROLE_NAME, param.getRoleName())
            .ne(Role.ROLE_ID, param.getRoleId())
        );
        if (existRoleNameFlag) {
            return AjaxResult.failed("角色名称已存在");
        }
        boolean existRoleKeyFlag = roleMapper.exists(new QueryWrapper<Role>()
            .eq(Role.ROLE_KEY, param.getRoleKey())
            .ne(Role.ROLE_ID, param.getRoleId())
        );
        if (existRoleKeyFlag) {
            return AjaxResult.failed("权限字符已存在");
        }

        // 如果是超级管理员不给编辑
        if (RoleConstant.SUPER_ADMIN_ROLE_KEY.equals(role.getRoleKey())) {
            return AjaxResult.failed("该角色不允许编辑");
        }

        try {
            editRoleHandle(param);
        } catch (Exception e) {
            return AjaxResult.failed("角色编辑失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 删除角色
     *
     * @param roleId 角色ID
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<Void> deleteRole(Long roleId) {
        if (Objects.isNull(roleId) || roleId.equals(0L)) {
            return AjaxResult.failed("角色ID不能为空");
        }

        Role role = roleMapper.selectById(roleId);
        if (Objects.isNull(role)) {
            return AjaxResult.failed("角色不存在");
        }
        if (RoleConstant.SUPER_ADMIN_ROLE_KEY.equals(role.getRoleKey())) {
            return AjaxResult.failed("该角色不允许删除");
        }

        // 判断角色是否被用户绑定

        try {
            deleteRoleHandle(roleId);
        } catch (Exception e) {
            return AjaxResult.failed("角色删除失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 更改角色状态
     *
     * @param param 请求参数
     * @return 更改结果
     */
    @Override
    public AjaxResult<Void> changeStatus(RoleChangeStatusParam param) {
        AjaxResult<Void> check = RoleChangeStatusParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        if (unExistByRoleId(param.getRoleId())) {
            return AjaxResult.failed("角色不存在");
        }

        boolean flag = roleMapper.updateById(Role
            .builder()
            .roleId(param.getRoleId())
            .status(param.getStatus())
            .build()
        ) > 0;
        if (!flag) {
            return AjaxResult.failed("角色更改状态失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 获取角色授权用户列表
     *
     * @param param 请求参数
     * @return 允许角色授权用户列表
     */
    @Override
    public AjaxResult<PaginationVo<UserVo>> authUserList(RoleAuthUserParam param) {
        AjaxResult<Void> check = RoleAuthUserParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        List<UserVo> userVoList = new ArrayList<>();

        UserRequest userRequest = UserConvert.toUserRequest(param);

        int total = userMapper.selectUserCount(userRequest);
        List<User> userList = userMapper.selectUserList(userRequest);
        if (CollectionUtils.isNotEmpty(userList)) {
            for (User user : userList) {
                userVoList.add(UserConvert.toUserVo(user));
            }
        }

        return AjaxResult.succeedWith(PaginationVo
            .<UserVo>builder()
            .total(total)
            .rows(userVoList)
            .build()
        );
    }

    /**
     * 获取允许角色授权用户列表
     *
     * @param param 请求参数
     * @return 允许角色授权用户列表
     */
    @Override
    public AjaxResult<PaginationVo<UserVo>> allowAuthUserList(RoleAuthUserParam param) {
        AjaxResult<Void> check = RoleAuthUserParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        List<UserVo> userVoList = new ArrayList<>();

        UserRequest userRequest = UserConvert.toUserRequest(param);

        int total = userMapper.selectAllowAuthUserCount(userRequest);
        List<User> allowUserList = userMapper.selectAllowAuthUserList(userRequest);

        if (CollectionUtils.isNotEmpty(allowUserList)) {
            for (User allowUser : allowUserList) {
                userVoList.add(UserConvert.toUserVo(allowUser));
            }
        }

        return AjaxResult.succeedWith(PaginationVo
            .<UserVo>builder()
            .total(total)
            .rows(userVoList)
            .build()
        );
    }

    /**
     * 批量添加授权用户
     *
     * @param param 请求参数
     * @return 批量添加结果
     */
    @Override
    public AjaxResult<Void> addAuthUserBatch(RoleAuthUserAddBatchParam param) {
        AjaxResult<Void> check = RoleAuthUserAddBatchParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        Role role = roleMapper.selectById(param.getRoleId());
        if (Objects.isNull(role)) {
            return AjaxResult.failed("角色不存在");
        }

        List<UserRole> userRoles = new ArrayList<>();
        for (Long userId : param.getUserIds()) {
            User user = userMapper.selectById(userId);
            if (Objects.isNull(user)) {
                return AjaxResult.failed("用户ID【" + userId + "】不存在");
            } else {
                long userRoleNum = userRoleMapper.selectCount(new QueryWrapper<UserRole>()
                    .eq(UserRole.ROLE_ID, param.getRoleId())
                    .eq(UserRole.USER_ID, userId)
                );
                if (userRoleNum < 1) {
                    userRoles.add(UserRole
                        .builder()
                        .roleId(param.getRoleId())
                        .userId(userId)
                        .build()
                    );
                }
            }
        }

        if (CollectionUtils.isNotEmpty(userRoles)) {
            boolean flag = userRoleService.saveBatch(userRoles);
            if (!flag) {
                return AjaxResult.failed("角色授权用户添加失败");
            }
        }

        return AjaxResult.succeed();
    }

    /**
     * 批量删除授权用户
     *
     * @param param 请求参数
     * @return 批量删除结果
     */
    @Override
    public AjaxResult<Void> deleteAuthUserBatch(RoleAuthUserDeleteBatchParam param) {
        AjaxResult<Void> check = RoleAuthUserDeleteBatchParam.check(param);
        if (!check.getIsSuccessful()) {
            return AjaxResult.failed(check.getMessage());
        }

        Role role = roleMapper.selectById(param.getRoleId());
        if (Objects.isNull(role)) {
            return AjaxResult.failed("角色不存在");
        }

        boolean flag = userRoleMapper.delete(new QueryWrapper<UserRole>()
            .eq(UserRole.ROLE_ID, param.getRoleId())
            .in(UserRole.USER_ID, param.getUserIds())
        ) > 0;
        if (!flag) {
            return AjaxResult.failed("角色授权用户删除失败");
        }

        return AjaxResult.succeed();
    }

    /**
     * 添加角色处理
     *
     * @param param 添加角色请求参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void addRoleHandle(RoleAddParam param) {
        Role role = Role
            .builder()
            .roleName(param.getRoleName())
            .roleKey(param.getRoleKey())
            .roleSort(param.getRoleSort())
            .status(param.getStatus())
            .remark(param.getRemark())
            .build();
        roleMapper.insert(role);

        if (CollectionUtils.isNotEmpty(param.getMenuIds())) {
            List<RoleMenu> roleMenus = param.getMenuIds()
                .stream()
                .map(menuId -> RoleMenu
                    .builder()
                    .roleId(role.getRoleId())
                    .menuId(menuId)
                    .build()
                )
                .collect(Collectors.toList());
            roleMenuService.saveBatch(roleMenus);
        }
    }

    /**
     * 编辑角色处理
     *
     * @param param 编辑角色请求参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void editRoleHandle(RoleEditParam param) {
        Role role = Role
            .builder()
            .roleId(param.getRoleId())
            .roleName(param.getRoleName())
            .roleKey(param.getRoleKey())
            .roleSort(param.getRoleSort())
            .status(param.getStatus())
            .remark(param.getRemark())
            .build();
        roleMapper.updateById(role);

        if (CollectionUtils.isNotEmpty(param.getMenuIds())) {
            // 删除原来的角色管理菜单
            roleMenuMapper.delete(new QueryWrapper<RoleMenu>()
                .eq(RoleMenu.ROLE_ID, param.getRoleId())
            );
            List<RoleMenu> roleMenus = param.getMenuIds()
                .stream()
                .map(menuId -> RoleMenu
                    .builder()
                    .roleId(role.getRoleId())
                    .menuId(menuId)
                    .build()
                )
                .collect(Collectors.toList());
            roleMenuService.saveBatch(roleMenus);
        }
    }

    /**
     * 删除角色处理
     *
     * @param roleId 角色ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteRoleHandle(Long roleId) {
        roleMapper.deleteById(roleId);
        roleMenuMapper.delete(new QueryWrapper<RoleMenu>()
            .eq(Role.ROLE_ID, roleId)
        );
    }

    /**
     * 根据角色ID判断角色是否不存在
     *
     * @param roleId 角色ID
     * @return Boolean
     */
    private Boolean unExistByRoleId(Long roleId) {
        return !roleMapper.exists(new QueryWrapper<Role>()
            .eq(Role.ROLE_ID, roleId)
        );
    }

}
